#pragma once
#include "mq_binding.hpp"
#include "mq_exchange.hpp"
#include "mq_queue.hpp"
#include "mq_message.hpp"

namespace mq
{
    class VirtualHost
    {
    public:
        using ptr = std::shared_ptr<VirtualHost>;
        VirtualHost(const std::string &host_name, const std::string &basedir, const std::string &dbfile)
            : _host_name(host_name),
              _mqmp(std::make_shared<MsgQueueManager>(dbfile)),
              _bmp(std::make_shared<BindingManager>(dbfile)),
              _mmp(std::make_shared<MessageManager>(basedir)),
              _emp(std::make_shared<ExchangeManager>(dbfile))
        {
            // 获取所有队列消息, 通过队列名称恢复消息数据
            QueueMap q_map = _mqmp->allQueue();
            for (auto &q : q_map)
            {
                _mmp->initQueueMessage(q.first);
            }
        }
        // 声明(创建)交换机
        bool declareExchange(const std::string &ename,
                             ExchangeType etype,
                             bool edurable,
                             bool eauto_delete,
                             const google::protobuf::Map<std::string, std::string> &eargs)
        {
            return _emp->declareExchange(ename, etype, edurable, eauto_delete, eargs);
        }
        // 删除交换机
        void deleteExchange(const std::string &ename)
        {
            // 删除交换机时要移除该交换机相关的binding信息
            _bmp->RemoveExchangeBinding(ename);
            _emp->deleteExchange(ename);
        }
        bool existsExchange(const std::string &name)
        {
            return _emp->IsExists(name);
        }
        Exchange::ptr selectExchange(const std::string &ename)
        {
            return _emp->selectExchange(ename);
        }
        // 声明(创建队列)
        bool declareQueue(const std::string &qname,
                          bool qdurbale,
                          bool qexclusive,
                          bool qauto_delete,
                          const google::protobuf::Map<std::string, std::string> &qargs)
        {
            // 初始化队列的消息存储管理类(队列消息管理句柄)
            _mmp->initQueueMessage(qname);
            // 创建一个队列
            return _mqmp->declareQueue(qname, qdurbale, qexclusive, qauto_delete, qargs);
        }
        void deleteQueue(const std::string qname)
        {
            // 删除要删除队列消息, 队列的binding信息
            _mmp->destroyQueueMessage(qname);
            _bmp->RemoveMsgQueueBinding(qname);
            _mqmp->deleteQueue(qname);
        }

        bool existsQueue(const std::string &name)
        {
            return _mqmp->IsExists(name);
        }

        QueueMap allQueues()
        {
            return _mqmp->allQueue();
        }

        bool Bind(const std::string &ename, const std::string &qname, const std::string &key)
        {
            Exchange::ptr ep = _emp->selectExchange(ename);
            if (ep.get() == nullptr)
            {
                LOG(ERROR) << "队列绑定失败, 交换机: " << ename << "不存在!\n";
                return false;
            }
            MsgQueue::ptr mqp = _mqmp->selectQueue(qname);
            if (mqp.get() == nullptr)
            {
                LOG(ERROR) << "队列绑定失败, 队列: " << qname << "不存在!\n";
                return false;
            }
            return _bmp->Bind(ename, qname, key, ep->durable && mqp->durable);
        }
        void unBind(const std::string &ename, const std::string &qname)
        {
            return _bmp->UnBind(ename, qname);
        }
        // 获取某个交换机bind的队列
        MsgQueueBindingMap ExchangeBindings(const std::string &ename)
        {
            return _bmp->getExchangeBindings(ename);
        }

        bool existsBinding(const std::string &ename, const std::string &qname)
        {
            return _bmp->IsExists(ename, qname);
        }

        // 推送消息(把一条消息插入到一个队列中)
        bool basicPublish(const std::string &qname, BasicProperties *bp, const std::string &body)
        {
            // 根据队列名称获取队列
            MsgQueue::ptr mqp = _mqmp->selectQueue(qname);
            if (mqp.get() == nullptr)
            {
                LOG(ERROR) << "消息推送失败, 队列: " << qname << "不存在!\n";
                return false;
            }
            return _mmp->insert(qname, bp, body, mqp->durable);
        }
        // 消费消息(消费某个队列中的消息)
        // 取出队列中的消息
        MessagePtr basicConsume(const std::string &qname)
        {
            // 取出消息会把消息从队列中移除, 并加入到待确认hash结构中
            // 等到ack确认就把消息从待确认的hash结构中移除;
            return _mmp->front(qname);
        }
        // 应答(应答某个队列中的某条消息(根据id判断), 然后将消息移出队列)
        void basicAck(const std::string &qname, const std::string &msg_id)
        {
            _mmp->ack(qname, msg_id);
        }

        void clear()
        {
            _emp->clear();
            _mqmp->Clear();
            _bmp->Clear();
            _mmp->clear();
        }

    private:
        std::string _host_name;
        MsgQueueManager::ptr _mqmp; // 队列管理(创建队列, 删除队列, 获取队列, 获取全部队列, 判断队列是否存在)
        ExchangeManager::ptr _emp;  // 交换机管理(创建, 删除, 获取, 判断是否存在)
        BindingManager::ptr _bmp;   // 绑定管理(建立, 解除, 判断, 移除交换机所有绑定, 移除队列所有绑定, 获取交换机所有相关绑定, 获取指定绑定)
        MessageManager::ptr _mmp;   // 整体队列及消息管理(取消息, 应答, 添加消息到队列, 销毁队列, 初始化队列管理句柄)
    };
}
